import math
import random
from django.shortcuts import redirect
from django.http.response import JsonResponse
from django.db import transaction
from django.forms.models import model_to_dict
from django.db.models import Count
import json
from .models import *
from .utils import *
import time,datetime
import re
from pathlib import Path
import os
def req_err(req):#^错误请求
    return JsonResponse({"status": 400, "message":"路径错误"})

def Login(req):#^登录
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect(["UserId","UserPassword"],data)#^监测是否携带对应参数
        if aa[0]:
            user=Information.objects.filter(UserId=data['UserId'])
            if user.exists() and user.first().UserPassword==data['UserPassword']:#^查询账号是否存在和密码是否符合
                if user.first().Isverified:#^判断是否已经激活
                    return JsonResponse({'status':200, 'message':"登录成功",'userid':user.first().UserId,'token':generateToken(user={"UserId":user.first().UserId,"UserName":user.first().UserName},key="blog-login",exp=int(time.time()) + 3600*3)})#^返回token
                else:
                    try:
                        send_sms_code(
                            to_email=[user.first().UserEmail],
                            message="邮箱验证",
                            html_message='''
                            <div align="left" valign="top" width="100%%"
                                style="font-family: 'Arial', sans-serif; font-size: 14px; line-height: 22px; color: #939598; padding: 30px 30px 30px;"
                                class="mobilePad">
                                <span style="color: #000000;"><b>尊敬的%s</b></span><br><br>
                                此验证邮件将于3分钟后失效，请立即<a
                                    href="http://127.0.0.1:52273/Verify?token=%s"
                                    target="_blank" style="color: #4dafd4; text-decoration: none;" rel="noopener"><b>前往验证</b></a>谢谢 。
                                感谢您帮助我们一同维护您的帐户安全。<br><br>
                                祝您体验愉快，<br>纸上花园
                            </div>
                            ''' % (user.first().UserName if user.first().UserName!="" else "未命名", generateToken(user={"UserId":user.first().UserId,"UserName":user.first().UserName},key="blog-verift",exp=int(time.time()) + 60*3))
                        )#^发送邮件
                        return JsonResponse({'status':400, 'message':"账号尚未认证，请前往认证"})
                    except:
                        Information.objects.filter(UserId=user.first().UserId).delete()
                        return JsonResponse({'status':400, 'message':"邮箱无效,请重新前往注册"})#^记录的邮箱无效
            else:
                return JsonResponse({'status':400, 'message':"账号或密码错误"})
    return JsonResponse({'status':400, 'message':"登录失败"})

def Register(req):#^注册
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect(["UserId","UserPassword","UserName","MyAutograph","MyBlog","UserEmail"],data)
        print(data,aa)
        if aa[0]:
            user=Information.objects.filter(UserId=data['UserId'])
            if user.exists():
                return JsonResponse({'status':400, 'message':"账号已存在"})
            else:
                if not data['UserEmail'] =="":
                    if bool(re.match(r"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$",data['UserEmail'])):
                        try:
                            send_sms_code(
                                to_email=[data['UserEmail']],
                                message="邮箱验证",
                                html_message='''
                                <div align="left" valign="top" width="100%%"
                                    style="font-family: 'Arial', sans-serif; font-size: 14px; line-height: 22px; color: #939598; padding: 30px 30px 30px;"
                                    class="mobilePad">
                                    <span style="color: #000000;"><b>尊敬的%s</b></span><br><br>
                                    此验证邮件将于3分钟后失效，请立即<a
                                        href="http://127.0.0.1:52273/Verify?token=%s"
                                        target="_blank" style="color: #4dafd4; text-decoration: none;" rel="noopener"><b>前往验证</b></a>谢谢 。
                                    感谢您帮助我们一同维护您的帐户安全。<br><br>
                                    祝您体验愉快，<br>纸上花园
                                </div>
                                ''' % (data['UserName'] if data['UserName']!="" else "未命名", generateToken(user={"UserId":data['UserId'],"UserName":data['UserName']},key="blog-verift",exp=int(time.time()) + 60*3))
                            )
                            cc=Information.objects.create(UserId=data['UserId'],UserName=data['UserName'],UserPassword=data['UserPassword'],MyAutograph=data['MyAutograph'],MyBlog=data['MyBlog'],UserEmail='',Identity=1,Integral=0,Isverified=False)
                            print(cc)
                            return JsonResponse({'status':200, 'message':"请查看邮箱"})
                        except:
                            return JsonResponse({'status':400, 'message':"邮箱无效"})
                    return JsonResponse({'status':400, 'message':"邮箱格式错误"})
                else:
                    Information.objects.create(UserId=data['UserId'],UserName=data['UserName'],UserPassword=data['UserPassword'],MyAutograph=data['MyAutograph'],MyBlog=data['MyBlog'],UserEmail='',Identity=1,Integral=0,Isverified=True)
                    return JsonResponse({'status':200, 'message':"注册成功，请前往登录"})
    return JsonResponse({'status':400, 'message':"注册错误"})

def verify(req):#^邮箱验证
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect(["token","UserID"],data)
        if aa[0]:
            key_,UserData=verify_jwt_token(key="blog-verift",token=data['token'])#^token解析
            if key_:
                if UserData['UserID']==data['UserID']:
                    Information.objects.filter(UserId=UserData['UserID']).update(Isverified=True)
                    return JsonResponse({'status':200, 'message':"验证成功，请前往登录"})
            else:
                return JsonResponse({'status':400, 'message':'无效链接'})
    return JsonResponse({'status':400, 'message':"验证失败"})
    
def Index(req):#^文章列表分页查询
     # 接收前端传过来的页码
    try:
        page = int(req.GET.get('page'))
    except:
        # 用户可能不是输入的整数
        page = 1
    if not page:
        page = 1
    try:
        count = int(req.GET.get('count'))
    except:
        # 用户可能不是输入的整数
        count = 8
    if not count:
        count = 8
    max_page = Release.objects.count()  # 总数
    page_list = [i for i in range(1, math.ceil(max_page / count) + 1)]  #^ 可以访问的页码
    # ceil 是math模块中 向上取整的函数
    Release_list = Release.objects.all().order_by('CreateTime')[page * count - count:page * count]  # 按照规则进行切片[1,2,3,4,5,6,7,8,9,10,11]
    result=list(Release_list.values())
    for i in range(len(result)):#range(3)->(0,1,2)
        result[i]['collection_count']=Release_list[i].collection_set.count()#^收藏数
        result[i]['Context']=result[i]['Context'][:160] if not result[i]['Preview'] else result[i]['Preview']#^文章预览
        result[i]['like_count']=Release_list[i].like_set.count()#^点赞量
        result[i]['news_count']=Release_list[i].news_set.count()#^评论量
        result[i]['Category_id']=Release_list[i].Category.CategoryName if Release_list[i].Category else None#^分类ID
    return JsonResponse({'status':200, 'message':"获取成功","releaselist":result,"pagelist":page_list})

def ReleaseAdd(req):#^文章发布
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect(["Title",["Tag",list],"Context","CategoryId","Preview",["Photo",int]],data)
        if aa[0]:
            with transaction.atomic():
                datetime_=datetime.datetime.today()
                # print(Category.objects.filter(CategoryId=data["CategoryId"]).first(),data["CategoryId"])
                try:
                    ArticleId=str(time.time())
                    obj=Release.objects.create(ArticleId=ArticleId,Title=data["Title"],Context=data["Context"],CreateTime=datetime_,UpdateTime=datetime_,Category=Category.objects.filter(CategoryId=data["CategoryId"]).first()  if data["CategoryId"] else None,Preview=data["Preview"],Photo=Files.objects.get(id=data['Photo']).FilePath)
                    for i in data['Tag']:
                        Label.objects.create(ArticleId=obj,Tag=i)
                    return JsonResponse({'status':200, 'message':"发布成功"})
                except Exception as e:
                    return JsonResponse({'status':400, 'message':"发布错误:{}".format(e)})
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"添加失败"})

def ReleaseDelete(req):#^文章删除
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect([["ArticleId",list]],data)
        if aa[0]:
            with transaction.atomic():
                # print(Category.objects.filter(CategoryId=data["CategoryId"]).first(),data["CategoryId"])
                try:
                    success=list()
                    fail=list()
                    for i in data['ArticleId']:
                        obj=Release.objects.filter(ArticleId=i)
                        success.append(i) if obj.exists() and obj.first().delete()[0] else fail.append(i) 
                    return JsonResponse({'status':200, 'message':{"success":success,"fail":fail}})

                except Exception as e:
                    return JsonResponse({'status':400, 'message':"删除失败",'e':e})
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"删除错误"})

def PutNew(req):#^发表评论
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect([["ArticleId",str],["Text",str],["ParentLevelId",int,type(None)]],data)
        if aa[0]:
            with transaction.atomic():
                try:
                    key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
                    obj=News.objects.create(ArticleId=Release.objects.filter(ArticleId=data['ArticleId']).first(),UserId=user_data['UserID'],Text=data['Text'],ParentLevelId=News.objects.filter(id=data['ParentLevelId']).first(),CreateTime=datetime.datetime.today())
                    if obj:
                        return JsonResponse({'status':200, 'message':"评论成功"})
                    else:
                        return JsonResponse({'status':400, 'message':"评论失败"})
                except:
                    pass
    return JsonResponse({'status':400, 'message':"失败"})
 
def GetDetails(req):#^查询文章详情
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect([["ArticleId",str]],data)
        if aa[0]:
            with transaction.atomic():
                key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
                article1=Release.objects.filter(ArticleId=data['ArticleId'])
                if article1.exists():
                    article=article1.first()
                    a=model_to_dict(article)#^模型转为字典
                    a['Tag']=list(i['Tag'] for i in article.label_set.all().values())#^标签列表
                    a['Category']=article.Category.CategoryName if article.Category else None#^所属类名
                    a['CollectionNum']=article.collection_set.count()#^收藏数
                    a['LikeNum']=article.like_set.all().count()#^点赞数
                    a['CreateTime']=article.CreateTime
                    a['IsLike']=Like.objects.filter(ArticleId=Release.objects.filter(ArticleId=a['ArticleId']).first(),UserId=Information.objects.filter(UserId=user_data['UserID']).first()).exists()#^是否点过赞
                    # if a['Photo']:
                    #     Photo=Files.objects.filter(id=a['Photo'])
                    #     if Photo.exists():
                    #         a['Photo']=Photo.first().FilePath
                    c=Release.objects.filter(ArticleId__gt=data['ArticleId']).all().order_by("ArticleId")#^上一篇，防止是第一个出错
                    a['Next']= c.first().ArticleId if c.exists() else None
                    c=Release.objects.filter(ArticleId__lt=data['ArticleId']).all().order_by("-ArticleId")#^下一篇，防止是最后一个出错
                    a['Previous']=c.first().ArticleId if c.exists() else None
                    #!消息等级组合
                    a['News']=[]
                    Newlist= News.objects.filter(ArticleId=data['ArticleId'])
                    a['NewsNum']=Newlist.count()
                    def level(NewsId):#^回调查询
                        obj=News.objects.filter(ParentLevelId_id=NewsId)
                        if obj.exists():
                            newslist=list()
                            for i in obj:
                                news=dict()
                                news['UserId']=i.UserId
                                arg=Information.objects.filter(UserId=i.UserId)
                                news["UserName"]=arg.first().UserName if arg.exists() else None#^防止用户注销出错
                                news['Text']=i.Text
                                news['CreateTime']=i.CreateTime
                                news['ChildNews']=level(i.id)
                                newslist.append(news)
                            return newslist
                                
                        else:
                            return None
                    #!消息头部初始化
                    for i in list(Newlist.filter(ParentLevelId_id=None).values()):
                        b=dict()
                        b['UserName']=Information.objects.filter(UserId=i['UserId']).first().UserName
                        # b['Category']=Category.objects.filter(Category_id=b['Category']).first().CategoryName
                        b['UserId']=i['UserId']
                        b['CreateTime']=i['CreateTime']
                        b['NewsId']=i['id']
                        b['ChildNews']=level(i['id'])
                        a['News'].append(b)
                    article1.update(Viewnum=article.Viewnum+1)#^浏览量自增
                    return JsonResponse({'status':200, 'message':a})

                else:
                    return JsonResponse({'status':400, 'message':"文章不存在"})
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"失败"})

def Search_screen(req):#^搜索筛选
    Title=req.GET.get('Title', None)
    CollectionId=req.GET.get('CollectionId', None)
    SortType=req.GET.get('SortType', None)
    Tag=req.GET.get('Tag', None)
    if Title or CollectionId or SortType or Tag:
        objs=Release.objects.all()
        if Title:
            objs=objs.filter(Title__contains=Title)
        if CollectionId:
            a=Category.objects.filter(CategoryId= CollectionId)
            if a.exists():
                objs=objs.filter(Category=a.first())
        if SortType:
            if SortType=='1':
                objs=objs.order_by("-Viewnum")#^根据观看数量排序
            elif SortType=='2':
                objs=objs.order_by("-CreateTime")#^根据发布时间排序
            elif SortType=='3':
                objs=objs.annotate(num_like=Count('like')).order_by("-num_like")#^视图添加新字段，并赋值为其他表中所属外键得数量，再按照新字段排序
            elif SortType=='4':
                objs=objs.annotate(num_news=Count('news')).order_by("-num_news")#^视图添加新字段，并赋值为其他表中所属外键得数量，再按照新字段排序
            elif SortType=='5':
                objs=objs.annotate(num_collection=Count('collection')).order_by("-num_collection")#^视图添加新字段，并赋值为其他表中所属外键得数量，再按照新字段排序
        if Tag:
            print(Tag)
            objs=objs.filter(label__Tag=Tag)#^查询外键中tag字段等于{tag}得数据
        result=list(objs.values())
        for i in range(len(result)):
            result[i]['collection_count']=objs[i].collection_set.count()
            result[i]['Context']=result[i]['Context'][:25]
            result[i]['like_count']=objs[i].like_set.count()
            result[i]['news_count']=objs[i].news_set.count()
            result[i]['Category_id']=objs[i].Category.CategoryName
        return JsonResponse({'status':200, 'message':"查询成功","data":result}) 
    else:
        return redirect("/index")

def LikeAdd(req):#^文章点赞
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect([["ArticleId",str]],data)
        if aa[0]:
            key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
            with transaction.atomic():
                article=Release.objects.filter(ArticleId=data['ArticleId'])
                information=Information.objects.filter(UserId=user_data['UserID'])
                if article.exists() and information.exists():
                    obj=Like.objects.filter(ArticleId=article.first(),UserId=information.first())
                    if obj.exists():
                        obj.delete()
                        return JsonResponse({'status':200, 'message':"取消点赞成功"}) 
                    else:
                        obj=Like.objects.create(ArticleId=article.first(),UserId=information.first())
                        if obj:
                            return JsonResponse({'status':200, 'message':"点赞成功"}) 
                        else:
                            return JsonResponse({'status':400, 'message':"点赞失败"}) 
                else:
                    return JsonResponse({'status':400, 'message':"文章不存在"}) 
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"失败"})

def CollectionAdd(req):#^文章收藏
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect([["ArticleId",str]],data)
        if aa[0]:
            key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
            with transaction.atomic():
                article=Release.objects.filter(ArticleId=data['ArticleId'])
                information=Information.objects.filter(UserId=user_data['UserID'])
                if article.exists() and information.exists():
                    obj=Collection.objects.filter(ArticleId=article.first(),UserId=information.first())
                    if obj.exists():
                        obj.delete()
                        return JsonResponse({'status':200, 'message':"取消收藏成功"}) 
                    else:
                        obj=Collection.objects.create(ArticleId=article.first(),UserId=information.first())
                        if obj:
                            return JsonResponse({'status':200, 'message':"收藏成功"}) 
                        else:
                            return JsonResponse({'status':400, 'message':"收藏失败"}) 
                else:
                    return JsonResponse({'status':400, 'message':"文章不存在"}) 
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"失败"})

def FileAdd(req):#^文件上传
    if req.method == 'POST':
        myFile = req.FILES.get("image")
        for i in req.FILES:
            print(i)
        if myFile:
            key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
            filename=str(int(time.time()))
            filetype=myFile.name.split('.')[1]
            if filetype in ('png', 'jpg', 'jpeg'):
                obj=Files.objects.create(FilePath="./static/{}".format(filename+'.'+filetype),UserId=Information.objects.filter(UserId=user_data['UserID']).first(),FileType=filetype)
                dir = os.path.join(os.path.join(Path(__file__).resolve().parent.parent, 'static'),'Avatar')
                with open(os.path.join(dir, filename+'.'+filetype), 'wb+') as destination:
                    for chunk in myFile.chunks():
                        destination.write(chunk)
                if obj:
                    return JsonResponse({'status':200, 'message':"上传成功【{}】".format(filename+"."+filetype),'filename':filename+"."+filetype})
                else:
                    return JsonResponse({'status':400, 'message':"上传失败"})
            else:
                JsonResponse({'status':400, 'message':"文件仅支持png、jpg、jpeg"})
    
    return JsonResponse({'status':400, 'message':"上传错误"})

def FileDel(req):#^文件删除
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect([["ImageId",str]],data)
        if aa[0]:
            key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
            obj=Files.objects.filter(id=data['ImageId'],UserId=Information.objects.filter(UserId=user_data['UserID']).first())
            if obj.exists():
                rm=obj.first().delete()
                if rm[0]:
                    return JsonResponse({'status':200, 'message':"文件已删除"})
                else:
                    return JsonResponse({'status':200, 'message':"文件删除失败"})
            else:
                return JsonResponse({'status':400, 'message':"文件不存在"})
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"失败"})

def FileList(req):#^查询自身文件列表列表
    result=list(Files.objects.filter(UserId=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))[1]['UserID']).values())
    for i in range(len(result)):
        del result[i]['UserId_id']
    return JsonResponse({'status':200, 'message':result})

def TagList(req):#^标签列表
    obj=Label.objects.all()
    result=set()
    for i in obj:
        result.add(i.Tag)
    return JsonResponse({'status':200, 'message':list(result)})

def CategoryList(req):#^分类列表
    obj=Category.objects.all().values()
    return JsonResponse({'status':200, 'message':list(obj)})

def CategoryAdd(req):#^添加分类
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect(["CategoryName",str],data)
        if aa[0]:
            obj=Category.objects.create(CategoryId=Category.objects.count+2,CategoryName=data['CategoryName'])
            if obj:
                return JsonResponse({'status':200, 'message':"上传成功【%s】"%data['CategoryName']})
            else:
                return JsonResponse({'status':400, 'message':"上传失败"})
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"添加错误"})

def CategoryDelete(req):#^删除分类
    if req.method == 'POST':
        try:
            data=json.loads(req.body)
        except:
            return JsonResponse({'status':400, 'message':"参数无法解析，JSON"})
        aa=Inspect(["CategoryId",str],data)
        if aa[0]:
            obj=Category.objects.delete(CategoryId=data['CategoryId'])
            if obj[0]:
                return JsonResponse({'status':200, 'message':"删除成功【%s】"%obj['CategoryId']})
            else:
                return JsonResponse({'status':400, 'message':"删除失败"})
        else:
            return JsonResponse({'status':400, 'message':"参数错误:{}".format(aa[1])})
    return JsonResponse({'status':400, 'message':"添加错误"})

def ChangeInfo(req):#^修改个人信息
    if req.method == 'POST':
        data=json.loads(req.body)
        info_data={
            "UserName":data.get('UserName',None),
            "UserAvatarUrl":data.get('UserAvatarUrl',None),
            "MyAutograph":data.get('MyAutograph',None),
            "UserPassword":data.get('UserPassword',None),
            "MyBlog":data.get('MyBlog',None),
            "UserEmail":data.get('UserEmail',None)
        }
        key,user_data=verify_jwt_token("blog-login",req.META.get("HTTP_TOKEN"))
        for i in list(info_data.keys()):
            if info_data[i] and type(info_data[i])!=str:
                return JsonResponse({'status':400, 'message':"{}类型不为string".format(i)})
            elif not info_data[i]:
                del info_data[i]
        if info_data.get('UserEmail',False) and not bool(re.match(r"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$",info_data['UserEmail'])):
            return  JsonResponse({'status':400, 'message':"邮箱格式错误"})
        if not bool(re.match(r"^https*://(www\.)?[\d|\w]*\.\w{2,4}/.*$",info_data.get('UserAvatarUrl',""))):
            return  JsonResponse({'status':400, 'message':"用户头像链接错误"})

        obj=Information.objects.filter(UserId=user_data['UserID']).update(**info_data)
        return  JsonResponse({'status':200, 'message':"更新完成"})
        # if ibj